﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DDD {

    /// <summary>
    /// バウンディングボックス
    /// </summary>
    /// <remarks>
    /// <dic>BouindgBox</dic>はノードを囲う軸に平行な６面の立方体でカリング、ピッキング、に使われます。
    /// コリジョン検出には使われません。
    /// バウンディングボックは<see cref="Node"/>に<see cref="BoundingVolume"/>コンポーネントを追加し、
    /// <see cref="BoundingVolume.SetBoundingBox(float,float, float, float, float, float)"/>メソッドによって付加されます。
    /// この<see cref="BoundingVolume"/>に付加されたバウンディングボックスをローカルのバウンディングボックスと言います。
    /// １つシーンが<see cref="World.Freeze"/>されるとシーンの下から子ノードのバウンディングボックスを囲うように
    /// ノードのバウンディングボックが形成されていきます。このノードのバウンディングボリュームを
    /// グローバルのバウンディングボックスと言います。
    /// またこのような階層構造をバウンディングボリューム階層といいます。
    /// ユーザーが<dic>BoundingBox</dic>型をインスタンス化することはできず、
    /// エンジン側が作成したものを戻り値で受け取ります。
    /// アニメート可能、エクスポート可能。
    /// </remarks>
    public struct BoundingBox : IAnimatable<float>, IExportable<float> {

        /// <summary>
        /// コンストラクター
        /// </summary>
        /// <param name="minX">X軸の下限</param>
        /// <param name="maxX">X軸の上限</param>
        /// <param name="minY">Y軸の下限</param>
        /// <param name="maxY">Y軸の上限</param>
        /// <param name="minZ">Z軸の下限</param>
        /// <param name="maxZ">Z軸の上限</param>
        internal BoundingBox (float minX, float maxX, float minY, float maxY, float minZ, float maxZ)
            : this () {
            this.MinX = minX;
            this.MaxX = maxX;
            this.MinY = minY;
            this.MaxY = maxY;
            this.MinZ = minZ;
            this.MaxZ = maxZ;
        }

        /// <summary>
        /// このバウンディングボックスの有効無効フラグ
        /// </summary>
        /// <remarks>
        /// このバウンディングボックスが有効なときtrueを返し、そうでない時はfalseを返します。
        /// </remarks>
        public bool IsValid {
            get { return true; }
        }

        /// <summary>
        /// X軸の下限
        /// </summary>
        /// <value>バウンディングボックスを形成するX軸方向の下限値です。</value>
        public float MinX { get; private set; }

        /// <summary>
        /// X軸の上限
        /// </summary>
        /// <value>バウンディングボックスを形成するX軸方向の上限値です。</value>
        public float MaxX { get; private set; }

        /// <summary>
        /// Y軸の下限
        /// </summary>
        /// <value>バウンディングボックスを形成するY軸方向の下限値です。</value>
        public float MinY { get; private set; }

        /// <summary>
        /// Y軸の上限
        /// </summary>
        /// <value>バウンディングボックスを形成するY軸方向の上限値です。</value>
        public float MaxY { get; private set; }

        /// <summary>
        /// Z軸の下限
        /// </summary>
        /// <value>バウンディングボックスを形成するZ軸方向の下限値です。</value>
        public float MinZ { get; private set; }

        /// <summary>
        /// Z軸の上限
        /// </summary>
        /// <value>バウンディングボックスを形成するZ軸方向の上限値です。</value>
        public float MaxZ { get; private set; }

        /// <summary>
        /// コンポーネント数
        /// </summary>
        /// <value>コンポーネント数です。バウンディングボックスなので常に6が返ります。</value>
        public int ComponentCount { get { return 6; } }

        /// <summary>
        /// コンポーネント要素にアクセスするインデクサ
        /// </summary>
        /// <param name="index">コンポーネント番号</param>
        /// <returns></returns>
        /// <exception cref="IndexOutOfRangeException"><dic>face &lt; 0 || face &gt; cc - 1</dic>の時<dic>IndexOutOfRange</dic></exception>
        public float this[int index] {
            get {
                if (index < 0 || index > ComponentCount - 1) {
                    throw new IndexOutOfRangeException ();
                }
                return 0;
            }
            set {
                if (index < 0 || index > ComponentCount - 1) {
                    throw new IndexOutOfRangeException ();
                }
                
            }
        }

        /// <summary>
        /// 現在のオブジェクトの状態を表す文字列を返します。
        /// </summary>
        /// <returns>現在のオブジェクトを説明する文字列</returns>
        public override string ToString () {
            return string.Format ("BoundingBox: MinX={0}, MaxX={1}, MinY={2}, MaxY={3}, MinZ={4}, MaxZ={5}", MinX, MaxX, MinY, MaxY, MinZ, MaxZ);
        }
    }
}
